/*******************************************************************************
 * Copyright © 2010-2020  陈恩点版权所有
 * Author: 陈恩点
 * First Create: 2012/8/21 11:49:53
 * Contact: 18115503914
 * Description: MyRapid快速开发框架
*********************************************************************************/
using System;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using MyRapid.Code;
using System.Configuration;
using System.Data.Common;
using System.Collections.Generic;
using System.Data;

namespace MyRapid.Server.Extension
{

    public class AuthenticationInspector : IDispatchMessageInspector
    {

        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            try
            {
                //消息只能被读取一次
                MessageBuffer requstBuffer = request.CreateBufferedCopy(int.MaxValue);
                Message msg = requstBuffer.CreateMessage();
                //多线程 保存日志
                Task task1 = new Task(() => SaveOperation(msg));
                task1.Start();
                request = requstBuffer.CreateMessage();
            }
            catch (Exception)
            {
            }

            //登录不需要验证
            if (request.Headers.Action.EndsWith("GetToken"))
                return null;

            //验证账号密码
            if (request.Headers.FindHeader("UserId", "Token") >= 0 && request.Headers.FindHeader("Password", "Token") >= 0)
            {
                string userid = request.Headers.GetHeader<string>("UserId", "Token");
                string password = request.Headers.GetHeader<string>("Password", "Token");
                LoginInf loginInf = Provider.GetLogin(password);
                if (loginInf == null)
                    throw new Exception("Authentication: Authorized Timeout !");
                if (userid != loginInf.UserId)
                    throw new Exception("Authentication: User Not Exists !");
                return null;
            }

            throw new Exception("Authentication: Not Authorized !");
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            MessageBuffer requstBuffer = reply.CreateBufferedCopy(int.MaxValue);
            Message msg = requstBuffer.CreateMessage();
            Task task1 = new Task(() => SaveOperation(msg));
            task1.Start();
            reply = requstBuffer.CreateMessage();

        }

        #region 保存操作日志
        //DbHelper db = new DbHelper(DbProviderType.SQLite, @"D:\wcf.db");

        private void SaveOperation(Message request)
        {
            //string sql = @"INSERT INTO Operation ( GUID,  Action,  WorkSet,  Parameters,  DataTable,  Message,  Address,  UserId,  UserName,  DateTime)
            //                               VALUES(@GUID, @Action, @WorkSet, @Parameters, @DataTable, @Message, @Address, @UserId, @UserName, @DateTime)";
            string action = request.Headers.Action;

            action = action.Substring(action.LastIndexOf("/") + 1, action.Length - action.LastIndexOf("/") - 1);
            RemoteEndpointMessageProperty pro = null;
            if (request.Properties.ContainsKey("System.ServiceModel.Channels.RemoteEndpointMessageProperty"))
            {
                pro = (RemoteEndpointMessageProperty)request.Properties["System.ServiceModel.Channels.RemoteEndpointMessageProperty"];
                //客户端地址： pro.Address
                //客户端端口： pro.Port
            }

            StringBuilder sb = new StringBuilder();
            XmlWriter xw = XmlWriter.Create(sb);

            request.WriteMessage(xw);
            xw.Flush();
            string s = sb.ToString();

            //File.AppendAllText(@"d:\log.log", s);

            XmlDocument xd = new XmlDocument();
            xd.LoadXml(s);

            XmlDocument nd = new XmlDocument();

            XmlHelper.ClearNameSpace(xd.ChildNodes, nd, nd);

            string x = nd.InnerXml;
            Envelope sd = XmlHelper.ToObject<Envelope>(x);
            if (pro != null && sd.Header != null)
                sd.Header.Client = new Client() { Address = pro.Address, Port = pro.Port };
            Saver.SaveEnvelope(sd);
            //File.AppendAllText(@"d:\log.log", sd.ToJson());
            //File.AppendAllText(@"d:\log.log", "\r\n\r\n\r\n");
        }
        #endregion
    }

    #region 消息对象

    public class Envelope
    {
        public Envelope()
        {
        }

        public Header Header { get; set; }

        public Body Body { get; set; }

    }

    public class Header
    {
        public Header()
        {
        }

        public string UserId { get; set; }

        public string Password { get; set; }

        public string HostName { get; set; }

        public string Action { get; set; }

        public Client Client { get; set; }

        public string MessageID { get; set; }

        public string RelatesTo { get; set; }

        public ReplyTo ReplyTo { get; set; }

        public string To { get; set; }

        public SequenceAcknowledgement SequenceAcknowledgement { get; set; }
    }

    public class Client
    {
        public Client()
        {
        }

        public string Address { get; set; }

        public int Port { get; set; }
    }

    public class SequenceAcknowledgement
    {
        public SequenceAcknowledgement() { }

        public string Identifier { get; set; }
    }

    public class ReplyTo
    {
        public ReplyTo() { }

        public string Address { get; set; }
    }

    public class Body
    {
        public Body()
        {

        }

        public GetData GetData { get; set; }

        public GetFilter GetFilter { get; set; }

        public SetData SetData { get; set; }

        public GetValue GetValue { get; set; }

        public Execute Execute { get; set; }

        public Fault Fault { get; set; }

        public GetFile GetFile { get; set; }

        public SetFile SetFile { get; set; }

        public string WorkSet_Id
        {
            get
            {
                string wk = "";
                if (GetData != null)
                    wk = GetData.WorkSet_Id;
                if (string.IsNullOrEmpty(wk) && (GetFilter != null))
                    wk = GetFilter.WorkSet_Id;
                if (string.IsNullOrEmpty(wk) && (SetData != null))
                    wk = SetData.WorkSet_Id;
                if (string.IsNullOrEmpty(wk) && (GetValue != null))
                    wk = GetValue.WorkSet_Id;
                if (string.IsNullOrEmpty(wk) && (Execute != null))
                    wk = Execute.WorkSet_Id;
                if (string.IsNullOrEmpty(wk) && (GetFile != null))
                    wk = GetFile.fileName;
                if (string.IsNullOrEmpty(wk) && (SetFile != null))
                    wk = SetFile.fileName;
                return wk;
            }
        }
        //public GetDataResponse GetDataResponse { get; set; }
        //public SetDataResponse SetDataResponse { get; set; }
        //public GetValueResponse GetValueResponse { get; set; }
        //public ExecuteResponse ExecuteResponse { get; set; }

    }

    #region 请求Body

    public class GetToken
    {
        public GetToken() { }

        public string userName { get; set; }

        public string password { get; set; }
    }

    public class GetData
    {
        public GetData() { }

        public string WorkSet_Id { get; set; }

        public List<MyParameter> sqlParameters { get; set; }
    }

    public class GetFilter
    {
        public GetFilter() { }

        public string WorkSet_Id { get; set; }

        public List<MyParameter> sqlParameters { get; set; }

        public string filterString { get; set; }
    }

    public class SetData
    {
        public SetData()
        {

        }

        public string WorkSet_Id { get; set; }

        public DataTable Data { get; set; }

        public List<MyParameter> sqlParameters { get; set; }
    }

    public class GetValue
    {
        public GetValue()
        {

        }

        public string WorkSet_Id { get; set; }

        public List<MyParameter> sqlParameters { get; set; }
    }

    public class Execute
    {
        public Execute()
        {

        }

        public string WorkSet_Id { get; set; }

        public List<MyParameter> sqlParameters { get; set; }
    }

    public class GetFile
    {
        public GetFile()
        {

        }

        public string fileName { get; set; }
    }

    public class SetFile
    {
        public SetFile()
        {

        }

        public string fileName { get; set; }
    }
    #endregion

    #region 返回数据Body

    public class GetDataResponse
    {
        public GetDataResponse() { }

        public DataTable GetDataResult { get; set; }
    }

    public class GetTokenResponse
    {
        public GetTokenResponse() { }

        public string GetTokenResult { get; set; }
    }

    public class GetValueResponse
    {
        public GetValueResponse() { }

        public object GetValueResult { get; set; }
    }

    public class SetDataResponse
    {
        public SetDataResponse() { }

        public int SetDataResult { get; set; }
    }

    public class ExecuteResponse
    {
        public ExecuteResponse() { }

        public int ExecuteResult { get; set; }
    }

    #endregion

    #region 返回错误Body

    public class Fault
    {
        public Fault() { }

        public Reason Reason { get; set; }

        public Code Code { get; set; }
    }


    public class Reason
    {
        public Reason() { }

        public string Text { get; set; }
    }


    public class Code
    {
        public Code() { }

        public string Value { get; set; }
    }

    #endregion

    #endregion

    #region 日志存储

    public static class Saver
    {

        public static void SaveEnvelope(Envelope envelope)
        {
            string logDB = ConfigurationManager.ConnectionStrings["logDB"].ConnectionString;
            DbHelper db = new DbHelper(DbProviderType.SqlServer, logDB);

            //"UserId"  TEXT,
            //"Password"  TEXT,
            //"Action"  TEXT,
            //"MessageID"  TEXT,
            //"RelatesTo"  TEXT,
            //"To"  TEXT,
            //"ReplyTo_Address"  TEXT,
            //"Client_Address"  TEXT,
            //"Client_Port"  TEXT,
            //"Identifier"  TEXT,
            //"Fault_Text"  TEXT,
            //"Fault_Value"  TEXT,
            //"Body"  TEXT
            string sqlInsert = @"INSERT INTO Envelope ([UserId]  ,[HostName]  ,[WorkSet] ,[Password]  ,[Action]  ,[MessageID]  ,[RelatesTo]  ,[Url]  ,[ReplyTo_Address]  ,[Client_Address]  ,[Client_Port]  ,[Identifier]  ,[Fault_Text]  ,[Fault_Value]  ,[Body] ,[LogTime]) 
                                                VALUES(@UserId  ,@HostName    ,@WorkSet ,@Password ,@Action ,@MessageID ,@RelatesTo ,@Url ,@ReplyTo_Address ,@Client_Address ,@Client_Port ,@Identifier ,@Fault_Text ,@Fault_Value ,@Body ,GETDATE())";


            List<DbParameter> mps = new List<DbParameter>();
            if (envelope.Header == null)
                envelope.Header = new Header();
            db.AddParameter(mps, "WorkSet", envelope.Body.WorkSet_Id ?? "");
            db.AddParameter(mps, "HostName", envelope.Header.HostName ?? "");
            db.AddParameter(mps, "UserId", envelope.Header.UserId ?? "");
            db.AddParameter(mps, "Password", envelope.Header.Password ?? "");
            db.AddParameter(mps, "Action", envelope.Header.Action ?? "");
            db.AddParameter(mps, "MessageID", envelope.Header.MessageID ?? "");
            db.AddParameter(mps, "RelatesTo", envelope.Header.RelatesTo ?? "");
            db.AddParameter(mps, "Url", envelope.Header.To ?? "");
            if (envelope.Header.ReplyTo == null)
                envelope.Header.ReplyTo = new ReplyTo();
            db.AddParameter(mps, "ReplyTo_Address", envelope.Header.ReplyTo.Address ?? "");
            if (envelope.Header.Client == null)
                envelope.Header.Client = new Client();
            db.AddParameter(mps, "Client_Address", envelope.Header.Client.Address ?? "");
            db.AddParameter(mps, "Client_Port", envelope.Header.Client.Port);
            if (envelope.Header.SequenceAcknowledgement == null)
                envelope.Header.SequenceAcknowledgement = new SequenceAcknowledgement();
            db.AddParameter(mps, "Identifier", envelope.Header.SequenceAcknowledgement.Identifier ?? "");
            if (envelope.Body == null)
                envelope.Body = new Body();
            if (envelope.Body.Fault == null)
                envelope.Body.Fault = new Fault();
            if (envelope.Body.Fault.Reason == null)
                envelope.Body.Fault.Reason = new Reason();
            if (envelope.Body.Fault.Code == null)
                envelope.Body.Fault.Code = new Code();
            db.AddParameter(mps, "Fault_Text", envelope.Body.Fault.Reason.Text ?? "");
            db.AddParameter(mps, "Fault_Value", envelope.Body.Fault.Code.Value ?? "");
            db.AddParameter(mps, "Body", envelope.Body.ToJson());

            db.ExecuteNonQuery(sqlInsert, mps);
        }
    }



    #endregion
}